# -*- coding: utf-8 -*-
"""
Tencent is pleased to support the open source community by making 蓝鲸智云PaaS平台社区版 (BlueKing PaaS Community
Edition) available.
Copyright (C) 2017-2021 THL A29 Limited, a Tencent company. All rights reserved.
Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://opensource.org/licenses/MIT
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.
"""
from django.http import JsonResponse, HttpResponse
from django.shortcuts import render
from blueapps.account import get_user_model
from django.conf import settings
import logging
from blueking.component.shortcuts import get_client_by_request
import time
import json
from functools import wraps
from django.core.exceptions import ValidationError
from home_application.constants import (
    MAX_ATTEMPTS, JOB_RESULT_ATTEMPTS_INTERVAL, JOB_BK_BIZ_ID, BK_JOB_HOST,
    WAITING_CODE, SUCCESS_CODE, WEB_SUCCESS_CODE, SEARCH_FILE_PLAN_ID,
    BACKUP_FILE_PLAN_ID
)
from home_application.models import BackupRecord, ApiRequestCount

logger = logging.getLogger(__name__)


def api_statistics_decorator(api_category, api_name):
    """API统计装饰器，记录API调用次数"""

    def decorator(func):
        @wraps(func)
        def wrapper(request, *args, **kwargs):
            try:
                # 记录API调用
                api_count, created = ApiRequestCount.objects.get_or_create(
                    api_category=api_category,
                    api_name=api_name,
                    defaults={'request_count': 0}
                )
                api_count.request_count += 1
                api_count.save()

                logger.info(f"API调用: {api_category}-{api_name}, 用户: {request.user.username}")
                return func(request, *args, **kwargs)
            except Exception as e:
                logger.error(f"API统计记录失败: {api_category}-{api_name}, 错误: {str(e)}")
                return func(request, *args, **kwargs)

        return wrapper

    return decorator


def exception_handler(func):
    """异常处理装饰器"""

    @wraps(func)
    def wrapper(request, *args, **kwargs):
        try:
            return func(request, *args, **kwargs)
        except ValidationError as e:
            logger.error(f"参数验证错误: {str(e)}")
            return JsonResponse({
                "code": 1,
                "message": f"参数错误: {str(e)}",
                "data": None
            })
        except Exception as e:
            logger.exception(f"接口异常: {func.__name__}, 错误: {str(e)}")
            return JsonResponse({
                "code": 1,
                "message": f"服务器异常: {str(e)}",
                "data": None
            })

    return wrapper


def validate_required_params(required_params):
    """参数验证装饰器"""

    def decorator(func):
        @wraps(func)
        def wrapper(request, *args, **kwargs):
            missing_params = []
            for param in required_params:
                if not request.GET.get(param):
                    missing_params.append(param)

            if missing_params:
                error_msg = f"缺少必需参数: {', '.join(missing_params)}"
                logger.warning(f"参数验证失败: {error_msg}")
                return JsonResponse({
                    "code": 1,
                    "message": error_msg,
                    "data": None
                })

            return func(request, *args, **kwargs)

        return wrapper

    return decorator


@exception_handler
def home(request):
    """首页"""
    return render(request, "home_application/index_home.html")


@exception_handler
def dev_guide(request):
    """开发指引"""
    return render(request, "home_application/dev_guide.html")


@exception_handler
def contact(request):
    """联系页"""
    return render(request, "home_application/contact.html")


@api_statistics_decorator("business", "get_bizs_list")
@exception_handler
def get_bizs_list(request):
    """获取业务列表"""
    logger.info("开始获取业务列表")

    # 从环境配置获取APP信息，从request获取当前用户信息
    client = get_client_by_request(request)
    # 请求参数
    kwargs = {
        "fields": [
            "bk_biz_id",
            "bk_biz_name"
        ],
        # 社区版环境中业务数量有限，故不考虑分页情况
        "page": {
            "start": 0,
            "limit": 10,
            "sort": ""
        }
    }
    # 这里需要填写对应的组件API的入口地址
    result = client.cc.search_business(kwargs)

    if result.get("result"):
        logger.info(f"业务列表获取成功，返回{len(result.get('data', {}).get('info', []))}条记录")
    else:
        logger.error(f"业务列表获取失败: {result.get('message')}")

    return JsonResponse(result)


@api_statistics_decorator("set", "get_sets_list")
@validate_required_params(["bk_biz_id"])
@exception_handler
def get_sets_list(request):
    """根据业务ID，查询业务下的集群列表"""
    bk_biz_id = request.GET.get('bk_biz_id')
    logger.info(f"开始获取业务{bk_biz_id}的集群列表")

    client = get_client_by_request(request)
    # 请求参数
    kwargs = {
        "bk_biz_id": bk_biz_id,  # 从request.GET中获取传递的查询参数
        "fields": ["bk_set_id", "bk_set_name", "bk_biz_id", "bk_created_at", "bk_supplier_account"],
    }
    result = client.cc.search_set(kwargs)

    if result.get("result"):
        logger.info(f"集群列表获取成功，业务{bk_biz_id}返回{len(result.get('data', {}).get('info', []))}条记录")
    else:
        logger.error(f"集群列表获取失败: {result.get('message')}")

    return JsonResponse(result)


@api_statistics_decorator("module", "get_modules_list")
@validate_required_params(["bk_biz_id", "bk_set_id"])
@exception_handler
def get_modules_list(request):
    """根据业务ID和集群ID，查询对应下辖的模块列表"""
    bk_biz_id = request.GET.get('bk_biz_id')
    bk_set_id = request.GET.get("bk_set_id")
    logger.info(f"开始获取业务{bk_biz_id}集群{bk_set_id}的模块列表")

    client = get_client_by_request(request)
    # 构造请求参数
    kwargs = {
        "bk_biz_id": bk_biz_id,
        "bk_set_id": bk_set_id,
        "fields": ["bk_module_id", "bk_module_name", "bk_set_id", "bk_biz_id", "bk_created_at", "bk_supplier_account"],
    }
    result = client.cc.search_module(kwargs)

    if result.get("result"):
        logger.info(
            f"模块列表获取成功，业务{bk_biz_id}集群{bk_set_id}返回{len(result.get('data', {}).get('info', []))}条记录")
    else:
        logger.error(f"模块列表获取失败: {result.get('message')}")

    return JsonResponse(result)


@api_statistics_decorator("host", "get_hosts_list")
@validate_required_params(["bk_biz_id"])
@exception_handler
def get_hosts_list(request):
    """获取主机列表，支持分页和过滤"""
    try:
        page = int(request.GET.get("page", 1))
        page_size = int(request.GET.get("page_size", 10))
    except ValueError:
        logger.warning("分页参数格式错误，使用默认值")
        page, page_size = 1, 10

    # 获取过滤参数
    bk_biz_id = request.GET.get("bk_biz_id")
    bk_set_id = request.GET.get("bk_set_id")
    bk_module_id = request.GET.get("bk_module_id")
    operator = request.GET.get("operator")

    logger.info(f"开始获取主机列表，业务ID: {bk_biz_id}, 页码: {page}, 页大小: {page_size}")

    start = (page - 1) * page_size

    # 构造请求参数
    kwargs = {
        "bk_biz_id": bk_biz_id,
        "page": {
            "start": start,
            "limit": page_size,
            "sort": ""
        },
        "fields": [
            "bk_host_id",
            "bk_host_innerip",
            "operator",
            "bk_bak_operator"
        ]
    }
    if bk_set_id:
        kwargs["bk_set_ids"] = [int(bk_set_id)]
    if bk_module_id:
        kwargs["bk_module_ids"] = [int(bk_module_id)]
    rules = []
    if operator:
        rules.append({
            "field": "operator",
            "operator": "contains",
            "value": operator
        })
    if rules:
        kwargs["host_property_filter"] = {
            "condition": "AND",
            "rules": rules
        }

    logger.info(f"主机分页查询参数: page={page}, page_size={page_size}, bk_biz_id={bk_biz_id}")

    try:
        client = get_client_by_request(request)
        result = client.cc.list_biz_hosts(kwargs)
        if result.get("result"):
            hosts = result.get("data", {}).get("info", [])
            count = result.get("data", {}).get("count", 0)
            logger.info(f"主机分页查询成功，返回{len(hosts)}条，总数{count}")
            return JsonResponse({
                "code": 0,
                "message": "success",
                "data": {
                    "info": hosts,
                    "count": count
                }
            })
        else:
            logger.error(f"主机分页查询失败: {result.get('message')}")
            return JsonResponse({
                "code": 1,
                "message": result.get("message", "查询失败"),
                "data": {
                    "info": [],
                    "count": 0
                }
            })
    except Exception as e:
        logger.exception("主机分页查询接口异常")
        return JsonResponse({
            "code": 1,
            "message": f"服务器异常: {str(e)}",
            "data": {
                "info": [],
                "count": 0
            }
        })


@api_statistics_decorator("host", "get_host_detail")
@validate_required_params(["bk_host_id"])
@exception_handler
def get_host_detail(request):
    """根据主机ID，查询主机详情信息"""
    bk_host_id = request.GET.get("bk_host_id")
    logger.info(f"开始获取主机{bk_host_id}的详情信息")

    client = get_client_by_request(request)

    kwargs = {
        "bk_host_id": bk_host_id
    }

    result = client.cc.get_host_base_info(kwargs)

    if result.get("result"):
        logger.info(f"主机详情获取成功: {bk_host_id}")
    else:
        logger.error(f"主机详情获取失败: {result.get('message')}")

    return JsonResponse(result)


@exception_handler
def set_super_user(request):
    """添加用户为管理员"""
    logger.info("开始设置超级用户")
    user = get_user_model()
    for name in settings.INIT_SUPERUSER:
        user.objects.update_or_create(
            username=name,
            defaults={'is_staff': True, 'is_active': True, 'is_superuser': True}
        )
    logger.info("超级用户设置完成")
    return HttpResponse('Success')


@api_statistics_decorator("log", "search_file")
@validate_required_params(["host_id_list", "search_path", "suffix"])
@exception_handler
def search_file(request):
    """
    根据主机IP、文件目录和文件后缀，查询符合条件的主机文件
    """
    host_id_list_str = request.GET.get("host_id_list")
    search_path = request.GET.get("search_path")
    suffix = request.GET.get("suffix")

    logger.info(f"开始文件搜索，主机列表: {host_id_list_str}, 搜索路径: {search_path}, 后缀: {suffix}")

    try:
        host_id_list = [int(bk_host_id) for bk_host_id in host_id_list_str.split(",")]
    except ValueError:
        logger.error("主机ID列表格式错误")
        return JsonResponse({
            "result": False,
            "code": WEB_SUCCESS_CODE,
            "message": "主机ID列表格式错误",
        })

    # 注意：先在constants.py中替换SEARCH_FILE_PLAN_ID为你自己在作业平台上新建的方案的ID
    kwargs = {
        "bk_scope_type": "biz",
        "bk_scope_id": JOB_BK_BIZ_ID,
        "job_plan_id": SEARCH_FILE_PLAN_ID,
        # TODO 修改为你创建的执行方案的全局变量
        "global_var_list": [
            {
                "name": "host_list",
                "server": {
                    "host_id_list": host_id_list,
                },
            },
            {
                "name": "search_path",
                "value": search_path,
            },
            {
                "name": "suffix",
                "value": suffix,
            },
        ],
    }

    try:
        # 调用执行方案
        client = get_client_by_request(request)
        job_instance_id = client.jobv3.execute_job_plan(**kwargs).get("data").get("job_instance_id")
        logger.info(f"作业执行方案已提交，作业实例ID: {job_instance_id}")

        kwargs = {
            "bk_scope_type": "biz",
            "bk_scope_id": JOB_BK_BIZ_ID,
            "job_instance_id": job_instance_id,
        }

        attempts = 0
        while attempts < MAX_ATTEMPTS:
            # 获取执行方案执行状态
            step_instance_list = client.jobv3.get_job_instance_status(**kwargs).get("data").get("step_instance_list")
            if step_instance_list[0].get("status") == WAITING_CODE:
                logger.debug(f"作业执行中，等待中... 尝试次数: {attempts + 1}")
                time.sleep(JOB_RESULT_ATTEMPTS_INTERVAL)
            elif step_instance_list[0].get("status") != SUCCESS_CODE:
                logger.error(f"作业执行失败，状态码: {step_instance_list[0].get('status')}")
                res_data = {
                    "result": False,
                    "code": WEB_SUCCESS_CODE,
                    "message": "search failed",
                }
                return JsonResponse(res_data)
            elif step_instance_list[0].get("status") == SUCCESS_CODE:
                logger.info("作业执行成功")
                break
            attempts += 1

        if attempts >= MAX_ATTEMPTS:
            logger.error("作业执行超时")
            return JsonResponse({
                "result": False,
                "code": WEB_SUCCESS_CODE,
                "message": "作业执行超时",
            })

        step_instance_id = step_instance_list[0].get("step_instance_id")
        log_list = []
        for bk_host_id in host_id_list:
            data = {
                "bk_scope_type": "biz",
                "bk_scope_id": JOB_BK_BIZ_ID,
                "job_instance_id": job_instance_id,
                "step_instance_id": step_instance_id,
                "bk_host_id": bk_host_id,
            }

            # 查询执行日志
            response = client.jobv3.get_job_instance_ip_log(**data).get("data")
            step_res = response.get("log_content")
            json_step_res = json.loads(step_res)

            json_step_res["bk_host_id"] = response.get("bk_host_id")
            log_list.append(json_step_res)

        logger.info(f"文件搜索完成，返回{len(log_list)}条记录")
        res_data = {
            "result": True,
            "code": WEB_SUCCESS_CODE,
            "data": log_list,
        }
        return JsonResponse(res_data)

    except Exception as e:
        logger.exception("文件搜索过程中发生异常")
        return JsonResponse({
            "result": False,
            "code": WEB_SUCCESS_CODE,
            "message": f"搜索异常: {str(e)}",
        })


@api_statistics_decorator("log", "backup_file")
@validate_required_params(["host_id_list", "search_path", "suffix", "backup_path"])
@exception_handler
def backup_file(request):
    """
    根据主机IP、文件目录和文件后缀，备份符合条件的主机文件到指定目录
    """
    host_id_list_str = request.GET.get("host_id_list")
    search_path = request.GET.get("search_path")
    suffix = request.GET.get("suffix")
    backup_path = request.GET.get("backup_path")
    logger.info(
        f"开始文件备份，主机列表: {host_id_list_str}, 搜索路径: {search_path}, 后缀: {suffix}, 备份路径: {backup_path}")

    try:
        host_id_list = [int(bk_host_id) for bk_host_id in host_id_list_str.split(",")]
    except (ValueError, AttributeError) as e:
        logger.error(f"主机ID列表格式错误: {str(e)}")
        return JsonResponse({
            "result": False,
            "code": WEB_SUCCESS_CODE,
            "message": "主机ID列表格式错误，请提供以逗号分隔的整数列表",
        })

    # 准备作业平台参数
    job_kwargs = {
        "bk_scope_type": "biz",
        "bk_scope_id": JOB_BK_BIZ_ID,
        "job_plan_id": BACKUP_FILE_PLAN_ID,
        "global_var_list": [
            {
                "name": "host_list",
                "server": {
                    "host_id_list": host_id_list,
                },
            },
            {
                "name": "search_path",
                "value": search_path
            },
            {
                "name": "suffix",
                "value": suffix
            },
            {
                "name": "backup_path",
                "value": backup_path,
            },
        ],
    }

    try:
        # 调用执行方案
        client = get_client_by_request(request)
        job_response = client.jobv3.execute_job_plan(**job_kwargs)
        job_instance_id = job_response.get("data", {}).get("job_instance_id")

        if not job_instance_id:
            logger.error(f"作业平台返回异常，无法获取job_instance_id: {job_response}")
            return JsonResponse({
                "result": False,
                "code": WEB_SUCCESS_CODE,
                "message": "作业平台返回异常，无法启动备份任务",
            })

        logger.info(f"备份作业执行方案已提交，作业实例ID: {job_instance_id}")

        # 准备状态查询参数
        status_kwargs = {
            "bk_scope_type": "biz",
            "bk_scope_id": JOB_BK_BIZ_ID,
            "job_instance_id": job_instance_id,
        }

        # 轮询作业状态
        for attempt in range(MAX_ATTEMPTS):
            status_response = client.jobv3.get_job_instance_status(**status_kwargs)
            step_instance_list = status_response.get("data", {}).get("step_instance_list", [])

            if not step_instance_list:
                logger.error(f"作业平台返回异常状态数据: {status_response}")
                return JsonResponse({
                    "result": False,
                    "code": WEB_SUCCESS_CODE,
                    "message": "作业平台返回异常状态数据",
                })

            step_status = step_instance_list[0].get("status")

            if step_status == WAITING_CODE:
                logger.debug(f"备份作业执行中，等待中... 尝试次数: {attempt + 1}")
                time.sleep(JOB_RESULT_ATTEMPTS_INTERVAL)
            elif step_status != SUCCESS_CODE:
                logger.error(f"备份作业执行失败，状态码: {step_status}")
                return JsonResponse({
                    "result": False,
                    "code": WEB_SUCCESS_CODE,
                    "message": f"备份失败，作业状态码: {step_status}",
                })
            else:
                logger.info("备份作业执行成功")
                break
        else:
            logger.error("备份作业执行超时")
            return JsonResponse({
                "result": False,
                "code": WEB_SUCCESS_CODE,
                "message": f"备份作业执行超时，最大尝试次数: {MAX_ATTEMPTS}",
            })

        # 处理成功的作业结果
        step_instance_id = step_instance_list[0].get("step_instance_id")
        backup_count = 0
        job_link = f"{BK_JOB_HOST}/biz/{JOB_BK_BIZ_ID}/execute/task/{job_instance_id}"
        operator = request.user.username

        for bk_host_id in host_id_list:
            log_data = {
                "bk_scope_type": "biz",
                "bk_scope_id": JOB_BK_BIZ_ID,
                "job_instance_id": job_instance_id,
                "step_instance_id": step_instance_id,
                "bk_host_id": bk_host_id,
            }

            # 查询执行日志
            log_response = client.jobv3.get_job_instance_ip_log(**log_data)
            log_content = log_response.get("data", {}).get("log_content", "[]")

            try:
                json_step_res = json.loads(log_content)
            except json.JSONDecodeError as e:
                logger.error(f"解析日志内容失败: {str(e)}, 主机ID: {bk_host_id}")
                continue

            for step_res in json_step_res:
                # 创建备份记录
                record_data = {
                    "bk_host_id": bk_host_id,
                    "bk_file_dir": search_path,
                    "bk_file_suffix": suffix,
                    "bk_file_operator": operator,
                    "bk_job_link": job_link,
                    **step_res
                }
                BackupRecord.objects.create(**record_data)
                backup_count += 1

        logger.info(f"文件备份完成，创建了{backup_count}条备份记录")
        return JsonResponse({
            "result": True,
            "data": "success",
            "code": WEB_SUCCESS_CODE,
        })

    except Exception as e:
        logger.exception("文件备份过程中发生异常")
        return JsonResponse({
            "result": False,
            "code": WEB_SUCCESS_CODE,
            "message": f"备份异常: {str(e)}",
        })


@api_statistics_decorator("backup", "get_backup_record")
@exception_handler
def get_backup_record(request):
    """查询备份记录（分页）"""
    logger.info("开始获取备份记录")

    try:
        # 获取分页参数，默认为第1页，每页10条
        page = int(request.GET.get("page", 1))
        page_size = int(request.GET.get("page_size", 10))
        start = (page - 1) * page_size
        end = start + page_size

        # 查询总数
        total_count = BackupRecord.objects.count()

        # 查询分页数据
        records = list(
            BackupRecord.objects.all()
            .order_by("-id")
            .values()[start:end]
        )
        logger.info(f"备份记录获取成功，返回{len(records)}条记录")

        return JsonResponse({
            "result": True,
            "data": {
                "info": records,
                "count": total_count
            },
            "code": WEB_SUCCESS_CODE,
        })
    except Exception as e:
        logger.exception("获取备份记录时发生异常")
        return JsonResponse({
            "result": False,
            "code": WEB_SUCCESS_CODE,
            "message": f"获取备份记录失败: {str(e)}",
            "data": {
                "info": [],
                "count": 0
            }
        })

@api_statistics_decorator("statistics", "get_api_statistics")
@exception_handler
def get_api_statistics(request):
    """获取API调用统计信息"""
    logger.info("开始获取API调用统计信息")

    try:
        # 获取所有API调用统计
        api_stats = ApiRequestCount.objects.all().order_by('-request_count')
        stats_data = [
            {
                'api_category': stat.api_category,
                'api_name': stat.api_name,
                'request_count': stat.request_count
            }
            for stat in api_stats
        ]

        # 按类别统计
        category_stats = {}
        for stat in api_stats:
            category = stat.api_category
            category_stats[category] = category_stats.get(category, 0) + stat.request_count

        # 计算总计
        total_requests = ApiRequestCount.objects.aggregate(total=sum('request_count'))['total'] or 0

        logger.info(f"API统计信息获取成功，共{len(stats_data)}个API，总请求数: {total_requests}")

        return JsonResponse({
            "result": True,
            "code": WEB_SUCCESS_CODE,
            "data": {
                "api_statistics": stats_data,
                "category_statistics": category_stats,
                "total_apis": len(stats_data),
                "total_requests": total_requests
            }
        })
    except Exception as e:
        logger.exception("获取API统计信息时发生异常")
        return JsonResponse({
            "result": False,
            "code": WEB_SUCCESS_CODE,
            "message": f"获取API统计信息失败: {str(e)}",
            "data": None
        })


@api_statistics_decorator("backup", "get_backup_record_by_host")
@validate_required_params(["bk_host_id"])
@exception_handler
def get_backup_record_by_host(request):
    """根据主机ID查询备份记录"""
    bk_host_id = request.GET.get("bk_host_id")
    logger.info(f"开始获取主机{bk_host_id}的备份记录")

    try:
        records = list(BackupRecord.objects.filter(
            bk_host_id=bk_host_id
        ).order_by("-id").values())

        logger.info(f"主机{bk_host_id}的备份记录获取成功，返回{len(records)}条记录")

        return JsonResponse({
            "result": True,
            "code": WEB_SUCCESS_CODE,
            "data": records
        })
    except Exception as e:
        logger.exception(f"获取主机{bk_host_id}备份记录时发生异常")
        return JsonResponse({
            "result": False,
            "code": WEB_SUCCESS_CODE,
            "message": f"获取备份记录失败: {str(e)}",
            "data": []
        })


@api_statistics_decorator("backup", "delete_backup_record")
@validate_required_params(["record_id"])
@exception_handler
def delete_backup_record(request):
    """删除备份记录"""
    record_id = request.GET.get("record_id")
    logger.info(f"开始删除备份记录{record_id}")

    try:
        record = BackupRecord.objects.get(id=record_id)
        record.delete()

        logger.info(f"备份记录{record_id}删除成功")

        return JsonResponse({
            "result": True,
            "code": WEB_SUCCESS_CODE,
            "message": "删除成功"
        })
    except BackupRecord.DoesNotExist:
        logger.warning(f"备份记录{record_id}不存在")
        return JsonResponse({
            "result": False,
            "code": WEB_SUCCESS_CODE,
            "message": "备份记录不存在"
        })
    except Exception as e:
        logger.exception(f"删除备份记录{record_id}时发生异常")
        return JsonResponse({
            "result": False,
            "code": WEB_SUCCESS_CODE,
            "message": f"删除失败: {str(e)}"
        })
